]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
shell: Move tray implementation away from GtkSocket
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 22 Dec 2022 19:02:28 +0000 (20:02 +0100)
committerMarge Bot <marge-bot@gnome.org>
Fri, 3 Mar 2023 13:34:44 +0000 (13:34 +0000)
Reimplement tray icon support on top of NaXembed. NaTrayIcon now
becomes a subclass of this type, replacing GtkSocket. The
ShellTrayIcon wrapper now embeds directly a NaTrayIcon, the
ShellEmbeddedWindow GTK widget and ShellGtkEmbed ClutterClone
objects are no longer necessary to wrap a NaXembed socket window.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2590>

15 files changed:
src/meson.build
src/shell-embedded-window-private.h [deleted file]
src/shell-embedded-window.c [deleted file]
src/shell-embedded-window.h [deleted file]
src/shell-gtk-embed.c [deleted file]
src/shell-gtk-embed.h [deleted file]
src/shell-tray-icon-private.h [new file with mode: 0644]
src/shell-tray-icon.c
src/shell-tray-icon.h
src/shell-tray-manager.c
src/tray/meson.build
src/tray/na-tray-child.c
src/tray/na-tray-child.h
src/tray/na-tray-manager.c
src/tray/na-tray-manager.h

index de88a45d9d9b401c36fdd48c2fb4e62fb2463588..b06b043a0bc90afc0ffb852508d4428c0513c9c4 100644 (file)
@@ -98,9 +98,7 @@ libshell_public_headers = [
   'shell-app-system.h',
   'shell-app-usage.h',
   'shell-blur-effect.h',
-  'shell-embedded-window.h',
   'shell-glsl-effect.h',
-  'shell-gtk-embed.h',
   'shell-global.h',
   'shell-invert-lightness-effect.h',
   'shell-action-modes.h',
@@ -128,6 +126,7 @@ libshell_private_headers = [
   'shell-app-cache-private.h',
   'shell-app-system-private.h',
   'shell-global-private.h',
+  'shell-tray-icon-private.h',
   'shell-window-tracker-private.h',
   'shell-wm-private.h'
 ]
@@ -138,11 +137,8 @@ libshell_sources = [
   'shell-app-system.c',
   'shell-app-usage.c',
   'shell-blur-effect.c',
-  'shell-embedded-window.c',
-  'shell-embedded-window-private.h',
   'shell-global.c',
   'shell-glsl-effect.c',
-  'shell-gtk-embed.c',
   'shell-invert-lightness-effect.c',
   'shell-keyring-prompt.c',
   'shell-keyring-prompt.h',
diff --git a/src/shell-embedded-window-private.h b/src/shell-embedded-window-private.h
deleted file mode 100644 (file)
index 5714af9..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-#ifndef __SHELL_EMBEDDED_WINDOW_PRIVATE_H__
-#define __SHELL_EMBEDDED_WINDOW_PRIVATE_H__
-
-#include "shell-embedded-window.h"
-#include "shell-gtk-embed.h"
-
-void _shell_embedded_window_set_actor (ShellEmbeddedWindow      *window,
-                                      ShellGtkEmbed            *embed);
-
-void _shell_embedded_window_allocate (ShellEmbeddedWindow *window,
-                                     int                  x,
-                                     int                  y,
-                                     int                  width,
-                                     int                  height);
-
-void _shell_embedded_window_map (ShellEmbeddedWindow *window);
-void _shell_embedded_window_unmap (ShellEmbeddedWindow *window);
-
-#endif /* __SHELL_EMBEDDED_WINDOW_PRIVATE_H__ */
diff --git a/src/shell-embedded-window.c b/src/shell-embedded-window.c
deleted file mode 100644 (file)
index 8fd6112..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#include "config.h"
-
-#include <gdk/gdkx.h>
-
-#include "shell-embedded-window-private.h"
-
-/* This type is a subclass of GtkWindow that ties the window to a
- * ShellGtkEmbed; the resizing logic is bound to the clutter logic.
- *
- * The typical usage we might expect is
- *
- *  - ShellEmbeddedWindow is created and filled with content
- *  - ShellEmbeddedWindow is shown with gtk_widget_show_all()
- *  - ShellGtkEmbed is created for the ShellEmbeddedWindow
- *  - actor is added to a stage
- *
- * The way it works is that the GtkWindow is mapped if and only if both:
- *
- * - gtk_widget_visible (window) [widget has been shown]
- * - Actor is mapped [actor and all parents visible, actor in stage]
- */
-
-enum {
-   PROP_0
-};
-
-typedef struct _ShellEmbeddedWindowPrivate ShellEmbeddedWindowPrivate;
-
-struct _ShellEmbeddedWindowPrivate {
-  ShellGtkEmbed *actor;
-
-  GdkRectangle position;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (ShellEmbeddedWindow,
-                            shell_embedded_window,
-                            GTK_TYPE_WINDOW);
-
-/*
- * The normal gtk_window_show() starts all of the complicated asynchronous
- * window resizing code running; we don't want or need any of that.
- * Bypassing the normal code does mean that the extra geometry management
- * available on GtkWindow: gridding, maximum sizes, etc, is ignored; we
- * don't really want that anyways - we just want a way of embedding a
- * GtkWidget into a Clutter stage.
- */
-static void
-shell_embedded_window_show (GtkWidget *widget)
-{
-  ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
-  ShellEmbeddedWindowPrivate *priv;
-  GtkWidgetClass *widget_class;
-
-  priv = shell_embedded_window_get_instance_private (window);
-
-  /* Skip GtkWindow, but run the default GtkWidget handling which
-   * marks the widget visible */
-  widget_class = g_type_class_peek (GTK_TYPE_WIDGET);
-  widget_class->show (widget);
-
-  if (priv->actor)
-    {
-      /* Size is 0x0 if the GtkWindow is not shown */
-      clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor));
-
-      if (clutter_actor_is_realized (CLUTTER_ACTOR (priv->actor)))
-        gtk_widget_map (widget);
-    }
-}
-
-static void
-shell_embedded_window_hide (GtkWidget *widget)
-{
-  ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
-  ShellEmbeddedWindowPrivate *priv;
-
-  priv = shell_embedded_window_get_instance_private (window);
-
-  if (priv->actor)
-    clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor));
-
-  GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->hide (widget);
-}
-
-static gboolean
-shell_embedded_window_configure_event (GtkWidget         *widget,
-                                       GdkEventConfigure *event)
-{
-  /* Normally a configure event coming back from X triggers the
-   * resizing logic inside GtkWindow; we just ignore them
-   * since we are handling the resizing logic separately.
-   */
-  return FALSE;
-}
-
-static void
-shell_embedded_window_check_resize (GtkContainer *container)
-{
-  ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (container);
-  ShellEmbeddedWindowPrivate *priv;
-
-  priv = shell_embedded_window_get_instance_private (window);
-
-  /* Check resize is called when a resize is queued on something
-   * inside the GtkWindow; we need to make sure that in response
-   * to this gtk_widget_size_request() and then
-   * gtk_widget_size_allocate() are called; we defer to the Clutter
-   * logic and assume it will do the right thing.
-   */
-  if (priv->actor)
-    clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->actor));
-}
-
-static GObject *
-shell_embedded_window_constructor (GType                  gtype,
-                                   guint                  n_properties,
-                                   GObjectConstructParam *properties)
-{
-  GObject *object;
-  GObjectClass *parent_class;
-
-  parent_class = G_OBJECT_CLASS (shell_embedded_window_parent_class);
-  object = parent_class->constructor (gtype, n_properties, properties);
-
-  /* Setting the resize mode to immediate means that calling queue_resize()
-   * on a widget within the window will immediately call check_resize()
-   * to be called, instead of having it queued to an idle. From our perspective,
-   * this is ideal since we just are going to queue a resize to Clutter's
-   * idle resize anyways.
-   */
-  g_object_set (object,
-                "app-paintable", TRUE,
-                "resize-mode", GTK_RESIZE_IMMEDIATE,
-                "type", GTK_WINDOW_POPUP,
-                NULL);
-
-  return object;
-}
-
-static void
-shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
-
-  object_class->constructor     = shell_embedded_window_constructor;
-
-  widget_class->show            = shell_embedded_window_show;
-  widget_class->hide            = shell_embedded_window_hide;
-  widget_class->configure_event = shell_embedded_window_configure_event;
-
-  container_class->check_resize    = shell_embedded_window_check_resize;
-}
-
-static void
-shell_embedded_window_init (ShellEmbeddedWindow *window)
-{
-}
-
-/*
- * Private routines called by ShellGtkEmbed
- */
-
-void
-_shell_embedded_window_set_actor (ShellEmbeddedWindow  *window,
-                                  ShellGtkEmbed        *actor)
-
-{
-  ShellEmbeddedWindowPrivate *priv;
-
-  g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window));
-
-  priv = shell_embedded_window_get_instance_private (window);
-  priv->actor = actor;
-
-  if (actor &&
-      clutter_actor_is_mapped (CLUTTER_ACTOR (actor)) &&
-      gtk_widget_get_visible (GTK_WIDGET (window)))
-    gtk_widget_map (GTK_WIDGET (window));
-}
-
-void
-_shell_embedded_window_allocate (ShellEmbeddedWindow *window,
-                                 int                  x,
-                                 int                  y,
-                                 int                  width,
-                                 int                  height)
-{
-  ShellEmbeddedWindowPrivate *priv;
-  GtkAllocation allocation;
-
-  g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window));
-
-  priv = shell_embedded_window_get_instance_private (window);
-
-  if (priv->position.x == x &&
-      priv->position.y == y &&
-      priv->position.width == width &&
-      priv->position.height == height)
-    return;
-
-  priv->position.x = x;
-  priv->position.y = y;
-  priv->position.width = width;
-  priv->position.height = height;
-
-  if (gtk_widget_get_realized (GTK_WIDGET (window)))
-    gdk_window_move_resize (gtk_widget_get_window (GTK_WIDGET (window)),
-                            x, y, width, height);
-
-  allocation.x = 0;
-  allocation.y = 0;
-  allocation.width = width;
-  allocation.height = height;
-
-  gtk_widget_size_allocate (GTK_WIDGET (window), &allocation);
-}
-
-void
-_shell_embedded_window_map (ShellEmbeddedWindow *window)
-{
-  g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window));
-
-  if (gtk_widget_get_visible (GTK_WIDGET (window)))
-    gtk_widget_map (GTK_WIDGET (window));
-}
-
-void
-_shell_embedded_window_unmap (ShellEmbeddedWindow *window)
-{
-  g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window));
-
-  gtk_widget_unmap (GTK_WIDGET (window));
-}
-
-/*
- * Public API
- */
-GtkWidget *
-shell_embedded_window_new (void)
-{
-  return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW,
-                       NULL);
-}
diff --git a/src/shell-embedded-window.h b/src/shell-embedded-window.h
deleted file mode 100644 (file)
index 835165b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-#ifndef __SHELL_EMBEDDED_WINDOW_H__
-#define __SHELL_EMBEDDED_WINDOW_H__
-
-#include <gtk/gtk.h>
-#include <clutter/clutter.h>
-
-#define SHELL_TYPE_EMBEDDED_WINDOW (shell_embedded_window_get_type ())
-G_DECLARE_DERIVABLE_TYPE (ShellEmbeddedWindow, shell_embedded_window,
-                          SHELL, EMBEDDED_WINDOW, GtkWindow)
-
-struct _ShellEmbeddedWindowClass
-{
-  GtkWindowClass parent_class;
-};
-
-GtkWidget *shell_embedded_window_new (void);
-
-#endif /* __SHELL_EMBEDDED_WINDOW_H__ */
diff --git a/src/shell-gtk-embed.c b/src/shell-gtk-embed.c
deleted file mode 100644 (file)
index 2ad18a1..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#include "config.h"
-
-#include "shell-embedded-window-private.h"
-#include "shell-global.h"
-#include "shell-util.h"
-
-#include <gdk/gdkx.h>
-#include <meta/display.h>
-#include <meta/window.h>
-
-enum {
-   PROP_0,
-
-   PROP_WINDOW
-};
-
-typedef struct _ShellGtkEmbedPrivate ShellGtkEmbedPrivate;
-
-struct _ShellGtkEmbedPrivate
-{
-  ShellEmbeddedWindow *window;
-
-  ClutterActor *window_actor;
-  gulong window_actor_destroyed_handler;
-
-  gulong window_created_handler;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_TYPE_CLONE);
-
-static void shell_gtk_embed_set_window (ShellGtkEmbed       *embed,
-                                        ShellEmbeddedWindow *window);
-
-static void
-shell_gtk_embed_on_window_destroy (GtkWidget     *object,
-                                   ShellGtkEmbed *embed)
-{
-  shell_gtk_embed_set_window (embed, NULL);
-}
-
-static void
-shell_gtk_embed_remove_window_actor (ShellGtkEmbed *embed)
-{
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  if (priv->window_actor)
-    {
-      g_clear_signal_handler (&priv->window_actor_destroyed_handler,
-                              priv->window_actor);
-
-      g_object_unref (priv->window_actor);
-      priv->window_actor = NULL;
-    }
-
-  clutter_clone_set_source (CLUTTER_CLONE (embed), NULL);
-}
-
-static void
-shell_gtk_embed_window_created_cb (MetaDisplay   *display,
-                                   MetaWindow    *window,
-                                   ShellGtkEmbed *embed)
-{
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-  Window xwindow = meta_window_get_xwindow (window);
-  GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (priv->window));
-
-  if (gdk_window && xwindow == gdk_x11_window_get_xid (gdk_window))
-    {
-      ClutterActor *window_actor =
-        CLUTTER_ACTOR (meta_window_get_compositor_private (window));
-      GCallback remove_cb = G_CALLBACK (shell_gtk_embed_remove_window_actor);
-      cairo_region_t *empty_region;
-
-      clutter_clone_set_source (CLUTTER_CLONE (embed), window_actor);
-
-      /* We want to explicitly clear the clone source when the window
-         actor is destroyed because otherwise we might end up keeping
-         it alive after it has been disposed. Otherwise this can cause
-         a crash if there is a paint after mutter notices that the top
-         level window has been destroyed, which causes it to dispose
-         the window, and before the tray manager notices that the
-         window is gone which would otherwise reset the window and
-         unref the clone */
-      priv->window_actor = g_object_ref (window_actor);
-      priv->window_actor_destroyed_handler =
-        g_signal_connect_swapped (window_actor,
-                                  "destroy",
-                                  remove_cb,
-                                  embed);
-
-      /* Hide the original actor otherwise it will appear in the scene
-         as a normal window */
-      clutter_actor_set_opacity (window_actor, 0);
-
-      /* Also make sure it (or any of its children) doesn't block
-         events on wayland */
-      shell_util_set_hidden_from_pick (window_actor, TRUE);
-
-      /* Set an empty input shape on the window so that it can't get
-         any input. This probably isn't the ideal way to achieve this.
-         It would probably be better to force the window to go behind
-         Mutter's guard window, but this is quite difficult to do as
-         Mutter doesn't manage the stacking for override redirect
-         windows and the guard window is repeatedly lowered to the
-         bottom of the stack. */
-      empty_region = cairo_region_create ();
-      gdk_window_input_shape_combine_region (gdk_window,
-                                             empty_region,
-                                             0, 0 /* offset x/y */);
-      cairo_region_destroy (empty_region);
-
-      gdk_window_lower (gdk_window);
-
-      /* Now that we've found the window we don't need to listen for
-         new windows anymore */
-      g_clear_signal_handler (&priv->window_created_handler,
-                              display);
-    }
-}
-
-static void
-shell_gtk_embed_on_window_mapped (GtkWidget     *object,
-                                  ShellGtkEmbed *embed)
-{
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-  MetaDisplay *display = shell_global_get_display (shell_global_get ());
-
-  if (priv->window_created_handler == 0 && priv->window_actor == NULL)
-    /* Listen for new windows so we can detect when Mutter has
-       created a MutterWindow for this window */
-    priv->window_created_handler =
-      g_signal_connect (display,
-                        "window-created",
-                        G_CALLBACK (shell_gtk_embed_window_created_cb),
-                        embed);
-}
-
-static void
-shell_gtk_embed_set_window (ShellGtkEmbed       *embed,
-                            ShellEmbeddedWindow *window)
-{
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-  MetaDisplay *display = shell_global_get_display (shell_global_get ());
-
-  if (priv->window)
-    {
-      g_clear_signal_handler (&priv->window_created_handler, display);
-
-      shell_gtk_embed_remove_window_actor (embed);
-
-      _shell_embedded_window_set_actor (priv->window, NULL);
-
-      g_object_unref (priv->window);
-
-      g_signal_handlers_disconnect_by_func (priv->window,
-                                            (gpointer)shell_gtk_embed_on_window_destroy,
-                                            embed);
-
-      g_signal_handlers_disconnect_by_func (priv->window,
-                                            (gpointer)shell_gtk_embed_on_window_mapped,
-                                            embed);
-    }
-
-  priv->window = window;
-
-  if (priv->window)
-    {
-      g_object_ref (priv->window);
-
-      _shell_embedded_window_set_actor (priv->window, embed);
-
-      g_signal_connect (priv->window, "destroy",
-                        G_CALLBACK (shell_gtk_embed_on_window_destroy), embed);
-
-      g_signal_connect (priv->window, "map",
-                        G_CALLBACK (shell_gtk_embed_on_window_mapped), embed);
-    }
-
-  clutter_actor_queue_relayout (CLUTTER_ACTOR (embed));
-}
-
-static void
-shell_gtk_embed_set_property (GObject         *object,
-                              guint            prop_id,
-                              const GValue    *value,
-                              GParamSpec      *pspec)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (object);
-
-  switch (prop_id)
-    {
-    case PROP_WINDOW:
-      shell_gtk_embed_set_window (embed, (ShellEmbeddedWindow *)g_value_get_object (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-shell_gtk_embed_get_property (GObject         *object,
-                              guint            prop_id,
-                              GValue          *value,
-                              GParamSpec      *pspec)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (object);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  switch (prop_id)
-    {
-    case PROP_WINDOW:
-      g_value_set_object (value, priv->window);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-shell_gtk_embed_get_preferred_width (ClutterActor *actor,
-                                     float         for_height,
-                                     float        *min_width_p,
-                                     float        *natural_width_p)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  if (priv->window
-      && gtk_widget_get_visible (GTK_WIDGET (priv->window)))
-    {
-      GtkRequisition min_req, natural_req;
-      gtk_widget_get_preferred_size (GTK_WIDGET (priv->window), &min_req, &natural_req);
-
-      *min_width_p = min_req.width;
-      *natural_width_p = natural_req.width;
-    }
-  else
-    *min_width_p = *natural_width_p = 0;
-}
-
-static void
-shell_gtk_embed_get_preferred_height (ClutterActor *actor,
-                                      float         for_width,
-                                      float        *min_height_p,
-                                      float        *natural_height_p)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  if (priv->window
-      && gtk_widget_get_visible (GTK_WIDGET (priv->window)))
-    {
-      GtkRequisition min_req, natural_req;
-      gtk_widget_get_preferred_size (GTK_WIDGET (priv->window), &min_req, &natural_req);
-
-      *min_height_p = min_req.height;
-      *natural_height_p = natural_req.height;
-    }
-  else
-    *min_height_p = *natural_height_p = 0;
-}
-
-static void
-shell_gtk_embed_allocate (ClutterActor          *actor,
-                          const ClutterActorBox *box)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-  float wx, wy;
-
-  CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)->
-    allocate (actor, box);
-
-  /* Find the actor's new coordinates in terms of the stage (which is
-   * priv->window's parent window.
-   */
-  clutter_actor_get_transformed_position (actor, &wx, &wy);
-
-  _shell_embedded_window_allocate (priv->window,
-                                   (int)(0.5 + wx), (int)(0.5 + wy),
-                                   box->x2 - box->x1,
-                                   box->y2 - box->y1);
-}
-
-static void
-shell_gtk_embed_map (ClutterActor *actor)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  _shell_embedded_window_map (priv->window);
-
-  CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)->map (actor);
-}
-
-static void
-shell_gtk_embed_unmap (ClutterActor *actor)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (actor);
-  ShellGtkEmbedPrivate *priv = shell_gtk_embed_get_instance_private (embed);
-
-  _shell_embedded_window_unmap (priv->window);
-
-  CLUTTER_ACTOR_CLASS (shell_gtk_embed_parent_class)->unmap (actor);
-}
-
-static void
-shell_gtk_embed_dispose (GObject *object)
-{
-  ShellGtkEmbed *embed = SHELL_GTK_EMBED (object);
-
-  G_OBJECT_CLASS (shell_gtk_embed_parent_class)->dispose (object);
-
-  shell_gtk_embed_set_window (embed, NULL);
-}
-
-static void
-shell_gtk_embed_class_init (ShellGtkEmbedClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
-
-  object_class->get_property = shell_gtk_embed_get_property;
-  object_class->set_property = shell_gtk_embed_set_property;
-  object_class->dispose      = shell_gtk_embed_dispose;
-
-  actor_class->get_preferred_width = shell_gtk_embed_get_preferred_width;
-  actor_class->get_preferred_height = shell_gtk_embed_get_preferred_height;
-  actor_class->allocate = shell_gtk_embed_allocate;
-  actor_class->map = shell_gtk_embed_map;
-  actor_class->unmap = shell_gtk_embed_unmap;
-
-  g_object_class_install_property (object_class,
-                                   PROP_WINDOW,
-                                   g_param_spec_object ("window",
-                                                        "Window",
-                                                        "ShellEmbeddedWindow to embed",
-                                                        SHELL_TYPE_EMBEDDED_WINDOW,
-                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void
-shell_gtk_embed_init (ShellGtkEmbed *embed)
-{
-}
-
-/*
- * Public API
- */
-ClutterActor *
-shell_gtk_embed_new (ShellEmbeddedWindow *window)
-{
-  g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL);
-
-  return g_object_new (SHELL_TYPE_GTK_EMBED,
-                       "window", window,
-                       NULL);
-}
diff --git a/src/shell-gtk-embed.h b/src/shell-gtk-embed.h
deleted file mode 100644 (file)
index 4cfc489..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-#ifndef __SHELL_GTK_EMBED_H__
-#define __SHELL_GTK_EMBED_H__
-
-#include <clutter/clutter.h>
-
-#include "shell-embedded-window.h"
-
-#define SHELL_TYPE_GTK_EMBED (shell_gtk_embed_get_type ())
-G_DECLARE_DERIVABLE_TYPE (ShellGtkEmbed, shell_gtk_embed,
-                          SHELL, GTK_EMBED, ClutterClone)
-
-struct _ShellGtkEmbedClass
-{
-    ClutterCloneClass parent_class;
-};
-
-ClutterActor *shell_gtk_embed_new (ShellEmbeddedWindow *window);
-
-#endif /* __SHELL_GTK_EMBED_H__ */
diff --git a/src/shell-tray-icon-private.h b/src/shell-tray-icon-private.h
new file mode 100644 (file)
index 0000000..e77ac0a
--- /dev/null
@@ -0,0 +1,11 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef SHELL_TRAY_ICON_PRIVATE_H
+#define SHELL_TRAY_ICON_PRIVATE_H
+
+#include "shell-tray-icon.h"
+
+#include "na-tray-child.h"
+
+ClutterActor * shell_tray_icon_new (NaTrayChild *tray_child);
+
+#endif /* SHELL_TRAY_ICON_PRIVATE_H */
index 14b219100aae3ac808dfa57d81055bf5d1375a8c..cac8016548c4f091245eec52f9c0b750cc6dab95 100644 (file)
@@ -2,13 +2,14 @@
 
 #include "config.h"
 
-#include "shell-tray-icon.h"
-#include "shell-gtk-embed.h"
+#include "shell-global.h"
+#include "shell-tray-icon-private.h"
+#include "shell-util.h"
 #include "tray/na-tray-child.h"
-#include <gdk/gdkx.h>
-#include <X11/Xatom.h>
 #include "st.h"
 
+#include <X11/Xatom.h>
+
 enum {
    PROP_0,
 
@@ -21,76 +22,86 @@ typedef struct _ShellTrayIconPrivate ShellTrayIconPrivate;
 
 struct _ShellTrayIcon
 {
-    ShellGtkEmbed parent;
-
-    ShellTrayIconPrivate *priv;
-};
-
-struct _ShellTrayIconPrivate
-{
-  NaTrayChild *socket;
+  ClutterClone parent;
+  NaTrayChild *tray_child;
+  ClutterActor *window_actor;
 
+  gulong window_actor_destroyed_handler;
+  gulong window_created_handler;
   pid_t pid;
-  char *title, *wm_class;
+  char *title;
+  char *wm_class;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (ShellTrayIcon, shell_tray_icon, SHELL_TYPE_GTK_EMBED);
+G_DEFINE_TYPE (ShellTrayIcon, shell_tray_icon, CLUTTER_TYPE_CLONE);
 
 static void
 shell_tray_icon_finalize (GObject *object)
 {
   ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
 
-  g_free (icon->priv->title);
-  g_free (icon->priv->wm_class);
+  g_free (icon->title);
+  g_free (icon->wm_class);
 
   G_OBJECT_CLASS (shell_tray_icon_parent_class)->finalize (object);
 }
 
 static void
-shell_tray_icon_constructed (GObject *object)
+shell_tray_icon_remove_window_actor (ShellTrayIcon *tray_icon)
 {
-  GdkWindow *icon_app_window;
-  ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
-  ShellEmbeddedWindow *window;
-  GdkDisplay *display;
-  Window plug_xid;
-  Atom _NET_WM_PID, type;
-  int result, format;
-  gulong nitems, bytes_after, *val = NULL;
-
-  /* We do all this now rather than computing it on the fly later,
-   * because the shell may want to see their values from a
-   * tray-icon-removed signal handler, at which point the plug has
-   * already been removed from the socket.
-   */
-
-  g_object_get (object, "window", &window, NULL);
-  g_return_if_fail (window != NULL);
-  icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window)));
-  g_object_unref (window);
-
-  icon->priv->title = na_tray_child_get_title (icon->priv->socket);
-  na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class);
+  if (tray_icon->window_actor)
+    {
+      g_clear_signal_handler (&tray_icon->window_actor_destroyed_handler,
+                              tray_icon->window_actor);
+      g_clear_object (&tray_icon->window_actor);
+    }
 
-  icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
-  plug_xid = GDK_WINDOW_XID (icon_app_window);
+  clutter_clone_set_source (CLUTTER_CLONE (tray_icon), NULL);
+}
 
-  display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
-  gdk_x11_display_error_trap_push (display);
-  _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
-  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
-                               _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
-                               &type, &format, &nitems,
-                               &bytes_after, (guchar **)&val);
-  if (!gdk_x11_display_error_trap_pop (display) &&
-      result == Success &&
-      type == XA_CARDINAL &&
-      nitems == 1)
-    icon->priv->pid = *val;
+static void
+shell_tray_icon_window_created_cb (MetaDisplay   *display,
+                                   MetaWindow    *window,
+                                   ShellTrayIcon *tray_icon)
+{
+  Window xwindow = meta_window_get_xwindow (window);
 
-  if (val)
-    XFree (val);
+  if (tray_icon->tray_child &&
+      xwindow == na_xembed_get_socket_window (NA_XEMBED (tray_icon->tray_child)))
+    {
+      ClutterActor *window_actor =
+        CLUTTER_ACTOR (meta_window_get_compositor_private (window));
+
+      clutter_clone_set_source (CLUTTER_CLONE (tray_icon), window_actor);
+
+      /* We want to explicitly clear the clone source when the window
+         actor is destroyed because otherwise we might end up keeping
+         it alive after it has been disposed. Otherwise this can cause
+         a crash if there is a paint after mutter notices that the top
+         level window has been destroyed, which causes it to dispose
+         the window, and before the tray manager notices that the
+         window is gone which would otherwise reset the window and
+         unref the clone */
+      tray_icon->window_actor = g_object_ref (window_actor);
+      tray_icon->window_actor_destroyed_handler =
+        g_signal_connect_swapped (window_actor,
+                                  "destroy",
+                                  G_CALLBACK (shell_tray_icon_remove_window_actor),
+                                  tray_icon);
+
+      /* Hide the original actor otherwise it will appear in the scene
+         as a normal window */
+      clutter_actor_set_opacity (window_actor, 0);
+
+      /* Also make sure it (or any of its children) doesn't block
+         events on wayland */
+      shell_util_set_hidden_from_pick (window_actor, TRUE);
+
+      /* Now that we've found the window we don't need to listen for
+         new windows anymore */
+      g_clear_signal_handler (&tray_icon->window_created_handler,
+                              display);
+    }
 }
 
 static void
@@ -104,15 +115,15 @@ shell_tray_icon_get_property (GObject         *object,
   switch (prop_id)
     {
     case PROP_PID:
-      g_value_set_uint (value, icon->priv->pid);
+      g_value_set_uint (value, icon->pid);
       break;
 
     case PROP_TITLE:
-      g_value_set_string (value, icon->priv->title);
+      g_value_set_string (value, icon->title);
       break;
 
     case PROP_WM_CLASS:
-      g_value_set_string (value, icon->priv->wm_class);
+      g_value_set_string (value, icon->wm_class);
       break;
 
     default:
@@ -121,14 +132,78 @@ shell_tray_icon_get_property (GObject         *object,
     }
 }
 
+static void
+shell_tray_icon_dispose (GObject *object)
+{
+  ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (object);
+  MetaDisplay *display = shell_global_get_display (shell_global_get ());
+
+  g_clear_signal_handler (&tray_icon->window_created_handler,
+                          display);
+  shell_tray_icon_remove_window_actor (tray_icon);
+
+  G_OBJECT_CLASS (shell_tray_icon_parent_class)->dispose (object);
+}
+
+static void
+shell_tray_icon_get_preferred_width (ClutterActor *actor,
+                                     float         for_height,
+                                     float        *min_width_p,
+                                     float        *natural_width_p)
+{
+  ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor);
+  int width;
+
+  na_xembed_get_size (NA_XEMBED (tray_icon->tray_child), &width, NULL);
+
+  *min_width_p = width;
+  *natural_width_p = width;
+}
+
+static void
+shell_tray_icon_get_preferred_height (ClutterActor *actor,
+                                      float         for_width,
+                                      float        *min_height_p,
+                                      float        *natural_height_p)
+{
+  ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor);
+  int height;
+
+  na_xembed_get_size (NA_XEMBED (tray_icon->tray_child), NULL, &height);
+
+  *min_height_p = height;
+  *natural_height_p = height;
+}
+
+static void
+shell_tray_icon_allocate (ClutterActor          *actor,
+                          const ClutterActorBox *box)
+{
+  ShellTrayIcon *tray_icon = SHELL_TRAY_ICON (actor);
+  float wx, wy;
+
+  CLUTTER_ACTOR_CLASS (shell_tray_icon_parent_class)->allocate (actor, box);
+
+  /* Find the actor's new coordinates in terms of the stage.
+   */
+  clutter_actor_get_transformed_position (actor, &wx, &wy);
+  na_xembed_set_root_position (NA_XEMBED (tray_icon->tray_child),
+                               (int)(0.5 + wx), (int)(0.5 + wy));
+}
+
 static void
 shell_tray_icon_class_init (ShellTrayIconClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
   object_class->get_property = shell_tray_icon_get_property;
-  object_class->constructed  = shell_tray_icon_constructed;
-  object_class->finalize     = shell_tray_icon_finalize;
+  object_class->finalize = shell_tray_icon_finalize;
+  object_class->dispose = shell_tray_icon_dispose;
+
+  actor_class->get_preferred_width = shell_tray_icon_get_preferred_width;
+  actor_class->get_preferred_height = shell_tray_icon_get_preferred_height;
+  actor_class->allocate = shell_tray_icon_allocate;
 
   g_object_class_install_property (object_class,
                                    PROP_PID,
@@ -156,20 +231,77 @@ shell_tray_icon_class_init (ShellTrayIconClass *klass)
 static void
 shell_tray_icon_init (ShellTrayIcon *icon)
 {
-  icon->priv = shell_tray_icon_get_instance_private (icon);
+}
+
+static void
+shell_tray_icon_set_child (ShellTrayIcon *tray_icon,
+                           NaTrayChild   *tray_child)
+{
+  MetaDisplay *display = shell_global_get_display (shell_global_get ());
+  MetaX11Display *x11_display;
+  Display *xdisplay;
+  Window plug_xid;
+  Atom type;
+  int result, format;
+  gulong nitems, bytes_after, *val = NULL;
+
+  g_return_if_fail (tray_icon != NULL);
+  g_return_if_fail (tray_child != NULL);
+
+  x11_display = meta_display_get_x11_display (display);
+
+  /* We do all this now rather than computing it on the fly later,
+   * because the shell may want to see their values from a
+   * tray-icon-removed signal handler, at which point the plug has
+   * already been removed from the socket.
+   */
+
+  tray_icon->tray_child = tray_child;
+
+  tray_icon->title = na_tray_child_get_title (tray_icon->tray_child);
+  na_tray_child_get_wm_class (tray_icon->tray_child,
+                              NULL, &tray_icon->wm_class);
+
+  plug_xid = na_xembed_get_plug_window (NA_XEMBED (tray_icon->tray_child));
+
+  xdisplay = meta_x11_display_get_xdisplay (x11_display);
+  meta_x11_error_trap_push (x11_display);
+  result = XGetWindowProperty (xdisplay, plug_xid,
+                               XInternAtom (xdisplay, "_NET_WM_PID", False),
+                               0, G_MAXLONG, False, XA_CARDINAL,
+                               &type, &format, &nitems,
+                               &bytes_after, (guchar **)&val);
+
+  if (!meta_x11_error_trap_pop_with_return (x11_display) &&
+      result == Success &&
+      type == XA_CARDINAL &&
+      nitems == 1)
+    tray_icon->pid = *val;
+
+  if (val)
+    XFree (val);
+
+  tray_icon->window_created_handler =
+    g_signal_connect (display,
+                      "window-created",
+                      G_CALLBACK (shell_tray_icon_window_created_cb),
+                      tray_icon);
 }
 
 /*
  * Public API
  */
 ClutterActor *
-shell_tray_icon_new (ShellEmbeddedWindow *window)
+shell_tray_icon_new (NaTrayChild *tray_child)
 {
-  g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL);
+  ShellTrayIcon *tray_icon;
+
+  g_return_val_if_fail (NA_IS_TRAY_CHILD (tray_child), NULL);
 
-  return g_object_new (SHELL_TYPE_TRAY_ICON,
-                       "window", window,
-                       NULL);
+  tray_icon = g_object_new (SHELL_TYPE_TRAY_ICON, NULL);
+  shell_tray_icon_set_child (tray_icon, tray_child);
+
+  return CLUTTER_ACTOR (tray_icon);
 }
 
 /**
@@ -187,37 +319,37 @@ void
 shell_tray_icon_click (ShellTrayIcon *icon,
                        ClutterEvent  *event)
 {
+  MetaDisplay *display = shell_global_get_display (shell_global_get ());
+  MetaX11Display *x11_display;
   XKeyEvent xkevent;
   XButtonEvent xbevent;
   XCrossingEvent xcevent;
-  GdkDisplay *display;
-  GdkWindow *remote_window;
-  GdkScreen *screen;
-  int x_root, y_root;
   Display *xdisplay;
   Window xwindow, xrootwindow;
   ClutterEventType event_type = clutter_event_type (event);
+  int width, height;
 
   g_return_if_fail (event_type == CLUTTER_BUTTON_RELEASE ||
                     event_type == CLUTTER_KEY_PRESS ||
                     event_type == CLUTTER_KEY_RELEASE);
 
-  remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
-  if (remote_window == NULL)
+  x11_display = meta_display_get_x11_display (display);
+  if (!x11_display)
+    return;
+
+  xwindow = na_xembed_get_plug_window (NA_XEMBED (icon->tray_child));
+  if (xwindow == None)
     {
       g_warning ("shell tray: plug window is gone");
       return;
     }
-  xdisplay = GDK_WINDOW_XDISPLAY (remote_window);
 
-  display = gdk_x11_lookup_xdisplay (xdisplay);
-  gdk_x11_display_error_trap_push (display);
+  na_xembed_get_size (NA_XEMBED (icon->tray_child), &width, &height);
 
-  xwindow = GDK_WINDOW_XID (remote_window);
-  screen = gdk_window_get_screen (remote_window);
-  xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
-  gdk_window_get_origin (remote_window, &x_root, &y_root);
+  meta_x11_error_trap_push (x11_display);
 
+  xdisplay = meta_x11_display_get_xdisplay (x11_display);
+  xrootwindow = XDefaultRootWindow (xdisplay);
 
   /* First make the icon believe the pointer is inside it */
   xcevent.type = EnterNotify;
@@ -225,10 +357,10 @@ shell_tray_icon_click (ShellTrayIcon *icon,
   xcevent.root = xrootwindow;
   xcevent.subwindow = None;
   xcevent.time = clutter_event_get_time (event);
-  xcevent.x = gdk_window_get_width (remote_window) / 2;
-  xcevent.y = gdk_window_get_height (remote_window) / 2;
-  xcevent.x_root = x_root + xcevent.x;
-  xcevent.y_root = y_root + xcevent.y;
+  xcevent.x = width / 2;
+  xcevent.y = height / 2;
+  xcevent.x_root = xcevent.x;
+  xcevent.y_root = xcevent.y;
   xcevent.mode = NotifyNormal;
   xcevent.detail = NotifyNonlinear;
   xcevent.same_screen = True;
@@ -290,5 +422,5 @@ shell_tray_icon_click (ShellTrayIcon *icon,
   xcevent.type = LeaveNotify;
   XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent);
 
-  gdk_x11_display_error_trap_pop_ignored (display);
+  meta_x11_error_trap_pop (x11_display);
 }
index f0e119114d07e79040817083c683c5947d24d7bb..434bd3d12969aa4a19e217b802f0f2ecd4efcafa 100644 (file)
@@ -2,15 +2,13 @@
 #ifndef __SHELL_TRAY_ICON_H__
 #define __SHELL_TRAY_ICON_H__
 
-#include "shell-gtk-embed.h"
+#include <clutter/clutter.h>
 
 #define SHELL_TYPE_TRAY_ICON (shell_tray_icon_get_type ())
 G_DECLARE_FINAL_TYPE (ShellTrayIcon, shell_tray_icon,
-                      SHELL, TRAY_ICON, ShellGtkEmbed)
+                      SHELL, TRAY_ICON, ClutterClone)
 
-ClutterActor *shell_tray_icon_new      (ShellEmbeddedWindow *window);
-
-void          shell_tray_icon_click    (ShellTrayIcon       *icon,
-                                        ClutterEvent        *event);
+void shell_tray_icon_click (ShellTrayIcon *icon,
+                            ClutterEvent  *event);
 
 #endif /* __SHELL_TRAY_ICON_H__ */
index c8e325978f6f9e3f55e618d006a55aba8fedccbf..4b332a87c07b903cb6decc99a9bcb4c671350ac4 100644 (file)
@@ -4,14 +4,12 @@
 
 #include <clutter/clutter.h>
 #include <girepository.h>
-#include <gtk/gtk.h>
 #include <meta/display.h>
 
 #include "shell-tray-manager.h"
 #include "na-tray-manager.h"
 
-#include "shell-tray-icon.h"
-#include "shell-embedded-window.h"
+#include "shell-tray-icon-private.h"
 #include "shell-global.h"
 
 typedef struct _ShellTrayManagerPrivate ShellTrayManagerPrivate;
@@ -33,8 +31,7 @@ struct _ShellTrayManagerPrivate {
 
 typedef struct {
   ShellTrayManager *manager;
-  GtkWidget *socket;
-  GtkWidget *window;
+  NaTrayChild *tray_child;
   ClutterActor *actor;
 } ShellTrayManagerChild;
 
@@ -60,15 +57,19 @@ static const ClutterColor default_color = { 0x00, 0x00, 0x00, 0xff };
 
 static void shell_tray_manager_release_resources (ShellTrayManager *manager);
 
-static void na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *child, gpointer manager);
-static void na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *child, gpointer manager);
+static void na_tray_icon_added (NaTrayManager *na_manager,
+                                NaTrayChild   *child,
+                                gpointer       manager);
+
+static void na_tray_icon_removed (NaTrayManager *na_manager,
+                                  NaTrayChild   *child,
+                                  gpointer       manager);
 
 static void
 free_tray_icon (gpointer data)
 {
   ShellTrayManagerChild *child = data;
 
-  gtk_widget_destroy (child->window);
   if (child->actor)
     {
       g_signal_handlers_disconnect_matched (child->actor, G_SIGNAL_MATCH_DATA,
@@ -188,13 +189,19 @@ shell_tray_manager_new (void)
 static void
 shell_tray_manager_ensure_resources (ShellTrayManager *manager)
 {
+  MetaDisplay *display;
+  MetaX11Display *x11_display;
+
   if (manager->priv->na_manager != NULL)
     return;
 
   manager->priv->icons = g_hash_table_new_full (NULL, NULL,
                                                 NULL, free_tray_icon);
 
-  manager->priv->na_manager = na_tray_manager_new ();
+  display = shell_global_get_display (shell_global_get ());
+  x11_display = meta_display_get_x11_display (display);
+
+  manager->priv->na_manager = na_tray_manager_new (x11_display);
 
   g_signal_connect (manager->priv->na_manager, "tray-icon-added",
                     G_CALLBACK (na_tray_icon_added), manager);
@@ -231,7 +238,7 @@ static void
 shell_tray_manager_manage_screen_internal (ShellTrayManager *manager)
 {
   shell_tray_manager_ensure_resources (manager);
-  na_tray_manager_manage_screen (manager->priv->na_manager);
+  na_tray_manager_manage (manager->priv->na_manager);
 }
 
 void
@@ -277,98 +284,63 @@ shell_tray_manager_unmanage_screen (ShellTrayManager *manager)
 }
 
 static void
-shell_tray_manager_child_on_realize (GtkWidget             *widget,
-                                     ShellTrayManagerChild *child)
-{
-  /* If the tray child is using an RGBA colormap (and so we have real
-   * transparency), we don't need to worry about the background. If
-   * not, we obey the bg-color property by creating a cairo pattern of
-   * that color and setting it as our background. Then "parent-relative"
-   * background on the socket and the plug within that will cause
-   * the icons contents to appear on top of our background color.
-   */
-  if (!na_tray_child_has_alpha (NA_TRAY_CHILD (child->socket)))
-    {
-      ClutterColor color = child->manager->priv->bg_color;
-      cairo_pattern_t *bg_pattern;
-
-      bg_pattern = cairo_pattern_create_rgb (color.red / 255.,
-                                             color.green / 255.,
-                                             color.blue / 255.);
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      gdk_window_set_background_pattern (gtk_widget_get_window (widget),
-                                         bg_pattern);
-G_GNUC_END_IGNORE_DEPRECATIONS
-
-      cairo_pattern_destroy (bg_pattern);
-    }
-}
-
-static void
-on_plug_added (GtkSocket        *socket,
+on_plug_added (NaTrayChild      *tray_child,
                ShellTrayManager *manager)
 {
   ShellTrayManagerChild *child;
 
-  g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager);
+  g_signal_handlers_disconnect_by_func (tray_child, on_plug_added, manager);
 
-  child = g_hash_table_lookup (manager->priv->icons, socket);
+  child = g_hash_table_lookup (manager->priv->icons, tray_child);
 
-  child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window));
+  child->actor = shell_tray_icon_new (tray_child);
   g_object_ref_sink (child->actor);
 
+  na_xembed_set_background_color (NA_XEMBED (tray_child),
+                                  &manager->priv->bg_color);
+
   g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
                  child->actor);
 }
 
 static void
-na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
-                    gpointer user_data)
+na_tray_icon_added (NaTrayManager *na_manager,
+                    NaTrayChild   *tray_child,
+                    gpointer       user_data)
 {
   ShellTrayManager *manager = user_data;
-  GtkWidget *win;
   ShellTrayManagerChild *child;
 
-  win = shell_embedded_window_new ();
-  gtk_container_add (GTK_CONTAINER (win), socket);
-
-  /* The visual of the socket matches that of its contents; make
-   * the window we put it in match that as well */
-  gtk_widget_set_visual (win, gtk_widget_get_visual (socket));
-
   child = g_new0 (ShellTrayManagerChild, 1);
   child->manager = manager;
-  child->window = win;
-  child->socket = socket;
-
-  g_signal_connect (win, "realize",
-                    G_CALLBACK (shell_tray_manager_child_on_realize), child);
+  child->tray_child = tray_child;
 
-  gtk_widget_show_all (win);
+  g_hash_table_insert (manager->priv->icons, tray_child, child);
 
-  g_hash_table_insert (manager->priv->icons, socket, child);
-
-  g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);
+  g_signal_connect (tray_child, "plug-added",
+                    G_CALLBACK (on_plug_added), manager);
 }
 
 static void
-na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *socket,
-                      gpointer user_data)
+na_tray_icon_removed (NaTrayManager *na_manager,
+                      NaTrayChild   *tray_child,
+                      gpointer       user_data)
 {
   ShellTrayManager *manager = user_data;
   ShellTrayManagerChild *child;
 
-  child = g_hash_table_lookup (manager->priv->icons, socket);
+  child = g_hash_table_lookup (manager->priv->icons, tray_child);
   g_return_if_fail (child != NULL);
 
   if (child->actor != NULL)
     {
       /* Only emit signal if a corresponding tray-icon-added signal was emitted,
-         that is, if embedding did not fail and we got a plug-added
-      */
+       * that is, if embedding did not fail and we got a plug-added
+       */
       g_signal_emit (manager,
                      shell_tray_manager_signals[TRAY_ICON_REMOVED], 0,
                      child->actor);
     }
-  g_hash_table_remove (manager->priv->icons, socket);
+
+  g_hash_table_remove (manager->priv->icons, tray_child);
 }
index 092e7f689bb6e4e5897f998d5085bf6c8e6a68a0..9d28e8cf19cf26ea99521f1996f61355b7c98335 100644 (file)
@@ -9,6 +9,6 @@ tray_sources = [
 
 libtray = static_library('tray', tray_sources,
   c_args: ['-DG_LOG_DOMAIN="notification_area"'],
-  dependencies: [mutter_dep, gtk_dep],
+  dependencies: [mutter_dep],
   include_directories: conf_inc
 )
index 175ac8a5a7cfe05c1fcc1ea7fb089938b283b890..1f1bae9b1a47f2a1101319af32268378d3d69a01 100644 (file)
 
 #include "na-tray-child.h"
 
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
 #include <X11/Xatom.h>
+#include <X11/Xutil.h>
 
-G_DEFINE_TYPE (NaTrayChild, na_tray_child, GTK_TYPE_SOCKET)
-
-static void
-na_tray_child_finalize (GObject *object)
-{
-  G_OBJECT_CLASS (na_tray_child_parent_class)->finalize (object);
-}
-
-static void
-na_tray_child_realize (GtkWidget *widget)
-{
-  NaTrayChild *child = NA_TRAY_CHILD (widget);
-  GdkVisual *visual = gtk_widget_get_visual (widget);
-  GdkWindow *window;
-
-  GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget);
-
-  window = gtk_widget_get_window (widget);
-
-  if (child->has_alpha)
-    {
-      /* We have real transparency with an ARGB visual and the Composite
-       * extension. */
-
-      /* Set a transparent background */
-      cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0);
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      gdk_window_set_background_pattern (window, transparent);
-G_GNUC_END_IGNORE_DEPRECATIONS
-      cairo_pattern_destroy (transparent);
-
-      child->parent_relative_bg = FALSE;
-    }
-  else if (visual == gdk_window_get_visual (gdk_window_get_parent (window)))
-    {
-      /* Otherwise, if the visual matches the visual of the parent window, we
-       * can use a parent-relative background and fake transparency. */
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      gdk_window_set_background_pattern (window, NULL);
-G_GNUC_END_IGNORE_DEPRECATIONS
-
-      child->parent_relative_bg = TRUE;
-    }
-  else
-    {
-      /* Nothing to do; the icon will sit on top of an ugly gray box */
-      child->parent_relative_bg = FALSE;
-    }
-
-  gtk_widget_set_app_paintable (GTK_WIDGET (child),
-                                child->parent_relative_bg || child->has_alpha);
-
-  /* Double-buffering will interfere with the parent-relative-background fake
-   * transparency, since the double-buffer code doesn't know how to fill in the
-   * background of the double-buffer correctly.
-   * The function is deprecated because it is only meaningful on X11 - the
-   * same is true for XEmbed of course, so just ignore the warning.
-   */
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-  gtk_widget_set_double_buffered (GTK_WIDGET (child),
-                                  child->parent_relative_bg);
-G_GNUC_END_IGNORE_DEPRECATIONS
-}
-
-static void
-na_tray_child_style_set (GtkWidget *widget,
-                         GtkStyle  *previous_style)
-{
-  /* The default handler resets the background according to the new style.
-   * We either use a transparent background or a parent-relative background
-   * and ignore the style background. So, just don't chain up.
-   */
-}
-
-#if 0
-/* This is adapted from code that was commented out in na-tray-manager.c; the
- * code in na-tray-manager.c wouldn't have worked reliably, this will. So maybe
- * it can be re-enabled. On other hand, things seem to be working fine without
- * it.
- *
- * If reenabling, you need to hook it up in na_tray_child_class_init().
- */
-static void
-na_tray_child_size_request (GtkWidget      *widget,
-                            GtkRequisition *request)
-{
-  GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_request (widget, request);
-
-  /*
-   * Make sure the icons have a meaningful size ..
-   */ 
-  if ((request->width < 16) || (request->height < 16))
-    {
-      gint nw = MAX (24, request->width);
-      gint nh = MAX (24, request->height);
-      g_warning ("Tray icon has requested a size of (%ix%i), resizing to (%ix%i)", 
-                 req.width, req.height, nw, nh);
-      request->width = nw;
-      request->height = nh;
-    }
-}
-#endif
-
-static void
-na_tray_child_size_allocate (GtkWidget      *widget,
-                             GtkAllocation  *allocation)
-{
-  NaTrayChild *child = NA_TRAY_CHILD (widget);
-  GtkAllocation widget_allocation;
-  gboolean moved, resized;
-
-  gtk_widget_get_allocation (widget, &widget_allocation);
-
-  moved = (allocation->x != widget_allocation.x ||
-          allocation->y != widget_allocation.y);
-  resized = (allocation->width != widget_allocation.width ||
-            allocation->height != widget_allocation.height);
-
-  /* When we are allocating the widget while mapped we need special handling
-   * for both real and fake transparency.
-   *
-   * Real transparency: we need to invalidate and trigger a redraw of the old
-   *   and new areas. (GDK really should handle this for us, but doesn't as of
-   *   GTK+-2.14)
-   *
-   * Fake transparency: if the widget moved, we need to force the contents to
-   *   be redrawn with the new offset for the parent-relative background.
-   */
-  if ((moved || resized) && gtk_widget_get_mapped (widget))
-    {
-      if (na_tray_child_has_alpha (child))
-        gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)),
-                                    &widget_allocation, FALSE);
-    }
-
-  GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget,
-                                                                allocation);
-
-  if ((moved || resized) && gtk_widget_get_mapped (widget))
-    {
-      if (na_tray_child_has_alpha (NA_TRAY_CHILD (widget)))
-        gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)),
-                                    &widget_allocation, FALSE);
-      else if (moved && child->parent_relative_bg)
-        na_tray_child_force_redraw (child);
-    }
-}
-
-/* The plug window should completely occupy the area of the child, so we won't
- * get a draw event. But in case we do (the plug unmaps itself, say), this
- * draw handler draws with real or fake transparency.
- */
-static gboolean
-na_tray_child_draw (GtkWidget *widget,
-                    cairo_t   *cr)
+struct _NaTrayChild
 {
-  NaTrayChild *child = NA_TRAY_CHILD (widget);
+  NaXembed parent_instance;
+  guint parent_relative_bg : 1;
+};
 
-  if (na_tray_child_has_alpha (child))
-    {
-      /* Clear to transparent */
-      cairo_set_source_rgba (cr, 0, 0, 0, 0);
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-      cairo_paint (cr);
-    }
-  else if (child->parent_relative_bg)
-    {
-      GdkWindow *window;
-      cairo_surface_t *target;
-      GdkRectangle clip_rect;
-
-      window = gtk_widget_get_window (widget);
-      target = cairo_get_group_target (cr);
-
-      gdk_cairo_get_clip_rectangle (cr, &clip_rect);
-
-      /* Clear to parent-relative pixmap
-       * We need to use direct X access here because GDK doesn't know about
-       * the parent relative pixmap. */
-      cairo_surface_flush (target);
-
-      XClearArea (GDK_WINDOW_XDISPLAY (window),
-                  GDK_WINDOW_XID (window),
-                  clip_rect.x, clip_rect.y,
-                  clip_rect.width, clip_rect.height,
-                  False);
-      cairo_surface_mark_dirty_rectangle (target,
-                                          clip_rect.x, clip_rect.y,
-                                          clip_rect.width, clip_rect.height);
-    }
-
-  return FALSE;
-}
+G_DEFINE_TYPE (NaTrayChild, na_tray_child, NA_TYPE_XEMBED)
 
 static void
 na_tray_child_init (NaTrayChild *child)
@@ -228,78 +41,47 @@ na_tray_child_init (NaTrayChild *child)
 static void
 na_tray_child_class_init (NaTrayChildClass *klass)
 {
-  GObjectClass *gobject_class;
-  GtkWidgetClass *widget_class;
-
-  gobject_class = (GObjectClass *)klass;
-  widget_class = (GtkWidgetClass *)klass;
-
-  gobject_class->finalize = na_tray_child_finalize;
-  widget_class->style_set = na_tray_child_style_set;
-  widget_class->realize = na_tray_child_realize;
-  widget_class->size_allocate = na_tray_child_size_allocate;
-  widget_class->draw = na_tray_child_draw;
 }
 
-GtkWidget *
-na_tray_child_new (GdkScreen *screen,
-                   Window     icon_window)
+NaTrayChild *
+na_tray_child_new (MetaX11Display *x11_display,
+                   Window          icon_window)
 {
   XWindowAttributes window_attributes;
-  GdkDisplay *display;
   Display *xdisplay;
   NaTrayChild *child;
-  GdkVisual *visual;
-  gboolean visual_has_alpha;
-  int red_prec, green_prec, blue_prec, depth;
   int result;
 
-  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  g_return_val_if_fail (META_IS_X11_DISPLAY (x11_display), NULL);
   g_return_val_if_fail (icon_window != None, NULL);
 
-  xdisplay = GDK_SCREEN_XDISPLAY (screen);
-  display = gdk_x11_lookup_xdisplay (xdisplay);
+  xdisplay = meta_x11_display_get_xdisplay (x11_display);
 
   /* We need to determine the visual of the window we are embedding and create
    * the socket in the same visual.
    */
 
-  gdk_x11_display_error_trap_push (display);
+  meta_x11_error_trap_push (x11_display);
   result = XGetWindowAttributes (xdisplay, icon_window,
                                  &window_attributes);
-  gdk_x11_display_error_trap_pop_ignored (display);
+  meta_x11_error_trap_pop (x11_display);
 
   if (!result) /* Window already gone */
     return NULL;
 
-  visual = gdk_x11_screen_lookup_visual (screen,
-                                         window_attributes.visual->visualid);
-  if (!visual) /* Icon window is on another screen? */
-    return NULL;
-
-  child = g_object_new (NA_TYPE_TRAY_CHILD, NULL);
-  child->icon_window = icon_window;
-
-  gtk_widget_set_visual (GTK_WIDGET (child), visual);
-
-  /* We have alpha if the visual has something other than red, green,
-   * and blue */
-  gdk_visual_get_red_pixel_details (visual, NULL, NULL, &red_prec);
-  gdk_visual_get_green_pixel_details (visual, NULL, NULL, &green_prec);
-  gdk_visual_get_blue_pixel_details (visual, NULL, NULL, &blue_prec);
-  depth = gdk_visual_get_depth (visual);
-
-  visual_has_alpha = red_prec + blue_prec + green_prec < depth;
-  child->has_alpha = visual_has_alpha;
+  child = g_object_new (NA_TYPE_TRAY_CHILD,
+                        "x11-display", x11_display,
+                        NULL);
 
-  return GTK_WIDGET (child);
+  return child;
 }
 
 char *
 na_tray_child_get_title (NaTrayChild *child)
 {
   char *retval = NULL;
-  GdkDisplay *display;
+  MetaX11Display *x11_display;
+  Display *xdisplay;
   Atom utf8_string, atom, type;
   int result;
   int format;
@@ -309,22 +91,23 @@ na_tray_child_get_title (NaTrayChild *child)
 
   g_return_val_if_fail (NA_IS_TRAY_CHILD (child), NULL);
 
-  display = gtk_widget_get_display (GTK_WIDGET (child));
+  x11_display = na_xembed_get_x11_display (NA_XEMBED (child));
+  xdisplay = meta_x11_display_get_xdisplay (x11_display);
 
-  utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
-  atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
+  utf8_string = XInternAtom (xdisplay, "UTF8_STRING", False);
+  atom = XInternAtom (xdisplay, "_NET_WM_NAME", False);
 
-  gdk_x11_display_error_trap_push (display);
+  meta_x11_error_trap_push (x11_display);
 
-  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
-                               child->icon_window,
+  result = XGetWindowProperty (xdisplay,
+                               na_xembed_get_plug_window (NA_XEMBED (child)),
                                atom,
                                0, G_MAXLONG,
                                False, utf8_string,
                                &type, &format, &nitems,
                                &bytes_after, (guchar **)&val);
-  
-  if (gdk_x11_display_error_trap_pop (display) || result != Success)
+
+  if (meta_x11_error_trap_pop_with_return (x11_display) || result != Success)
     return NULL;
 
   if (type != utf8_string ||
@@ -349,73 +132,6 @@ na_tray_child_get_title (NaTrayChild *child)
   return retval;
 }
 
-/**
- * na_tray_child_has_alpha;
- * @child: a #NaTrayChild
- *
- * Checks if the child has an ARGB visual and real alpha transparence.
- * (as opposed to faked alpha transparency with an parent-relative
- * background)
- *
- * Return value: %TRUE if the child has an alpha transparency
- */
-gboolean
-na_tray_child_has_alpha (NaTrayChild *child)
-{
-  g_return_val_if_fail (NA_IS_TRAY_CHILD (child), FALSE);
-
-  return child->has_alpha;
-}
-
-/* If we are faking transparency with a window-relative background, force a
- * redraw of the icon. This should be called if the background changes or if
- * the child is shifted with respect to the background.
- */
-void
-na_tray_child_force_redraw (NaTrayChild *child)
-{
-  GtkWidget *widget = GTK_WIDGET (child);
-
-  if (gtk_widget_get_mapped (widget) && child->parent_relative_bg)
-    {
-#if 1
-      /* Sending an ExposeEvent might cause redraw problems if the
-       * icon is expecting the server to clear-to-background before
-       * the redraw. It should be ok for GtkStatusIcon or EggTrayIcon.
-       */
-      GdkDisplay *display = gtk_widget_get_display (widget);
-      Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
-      XEvent xev;
-      GdkWindow *plug_window;
-      GtkAllocation allocation;
-
-      plug_window = gtk_socket_get_plug_window (GTK_SOCKET (child));
-      gtk_widget_get_allocation (widget, &allocation);
-
-      xev.xexpose.type = Expose;
-      xev.xexpose.window = GDK_WINDOW_XID (plug_window);
-      xev.xexpose.x = 0;
-      xev.xexpose.y = 0;
-      xev.xexpose.width = allocation.width;
-      xev.xexpose.height = allocation.height;
-      xev.xexpose.count = 0;
-
-      gdk_x11_display_error_trap_push (display);
-      XSendEvent (xdisplay,
-                  xev.xexpose.window,
-                  False, ExposureMask,
-                  &xev);
-      gdk_x11_display_error_trap_pop_ignored (display);
-#else
-      /* Hiding and showing is the safe way to do it, but can result in more
-       * flickering.
-       */
-      gdk_window_hide (widget->window);
-      gdk_window_show (widget->window);
-#endif
-    }
-}
-
 /* from libwnck/xutils.c, comes as LGPLv2+ */
 static char *
 latin1_to_utf8 (const char *latin1)
@@ -437,21 +153,22 @@ latin1_to_utf8 (const char *latin1)
 
 /* derived from libwnck/xutils.c, comes as LGPLv2+ */
 static void
-_get_wmclass (Display *xdisplay,
-              Window   xwindow,
-              char   **res_class,
-              char   **res_name)
+_get_wmclass (MetaX11Display  *x11_display,
+              Window           xwindow,
+              char           **res_class,
+              char           **res_name)
 {
-  GdkDisplay *display;
   XClassHint ch;
+  Display *xdisplay;
 
   ch.res_name = NULL;
   ch.res_class = NULL;
 
-  display = gdk_x11_lookup_xdisplay (xdisplay);
-  gdk_x11_display_error_trap_push (display);
+  xdisplay = meta_x11_display_get_xdisplay (x11_display);
+
+  meta_x11_error_trap_push (x11_display);
   XGetClassHint (xdisplay, xwindow, &ch);
-  gdk_x11_display_error_trap_pop_ignored (display);
+  meta_x11_error_trap_pop (x11_display);
 
   if (res_class)
     *res_class = NULL;
@@ -491,14 +208,14 @@ na_tray_child_get_wm_class (NaTrayChild  *child,
                             char        **res_name,
                             char        **res_class)
 {
-  GdkDisplay *display;
+  MetaX11Display *x11_display;
 
   g_return_if_fail (NA_IS_TRAY_CHILD (child));
 
-  display = gtk_widget_get_display (GTK_WIDGET (child));
+  x11_display = na_xembed_get_x11_display (NA_XEMBED (child));
 
-  _get_wmclass (GDK_DISPLAY_XDISPLAY (display),
-                child->icon_window,
+  _get_wmclass (x11_display,
+                na_xembed_get_plug_window (NA_XEMBED (child)),
                 res_class,
                 res_name);
 }
index d1436764248b0620a5afcdb04395934daf8fdd53..c50a0f92843257ae1084ce74fad06d51af628bc1 100644 (file)
 #ifndef __NA_TRAY_CHILD_H__
 #define __NA_TRAY_CHILD_H__
 
-#include <gtk/gtk.h>
-#include <gtk/gtkx.h>
+#include "na-xembed.h"
 
-G_BEGIN_DECLS
-
-#define NA_TYPE_TRAY_CHILD             (na_tray_child_get_type ())
-#define NA_TRAY_CHILD(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_CHILD, NaTrayChild))
-#define NA_TRAY_CHILD_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
-#define NA_IS_TRAY_CHILD(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_CHILD))
-#define NA_IS_TRAY_CHILD_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_CHILD))
-#define NA_TRAY_CHILD_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
-
-typedef struct _NaTrayChild      NaTrayChild;
-typedef struct _NaTrayChildClass  NaTrayChildClass;
-typedef struct _NaTrayChildChild  NaTrayChildChild;
+#include <meta/meta-x11-errors.h>
 
-struct _NaTrayChild
-{
-  GtkSocket parent_instance;
-  Window icon_window;
-  guint has_alpha : 1;
-  guint parent_relative_bg : 1;
-};
-
-struct _NaTrayChildClass
-{
-  GtkSocketClass parent_class;
-};
+G_BEGIN_DECLS
 
-GType           na_tray_child_get_type        (void);
+#define NA_TYPE_TRAY_CHILD (na_tray_child_get_type ())
+G_DECLARE_FINAL_TYPE (NaTrayChild, na_tray_child, NA, TRAY_CHILD, NaXembed)
 
-GtkWidget      *na_tray_child_new            (GdkScreen    *screen,
-                                              Window        icon_window);
+NaTrayChild    *na_tray_child_new            (MetaX11Display *x11_display,
+                                              Window          icon_window);
 char           *na_tray_child_get_title      (NaTrayChild  *child);
-gboolean        na_tray_child_has_alpha      (NaTrayChild  *child);
-void            na_tray_child_force_redraw   (NaTrayChild  *child);
 void            na_tray_child_get_wm_class   (NaTrayChild  *child,
                                              char        **res_name,
                                              char        **res_class);
index 15e1d80ec0506ff8447af668ab26ed50d39844be..1fbb7ac20472d3adb909b15ddf9e85a6c9616c2e 100644 (file)
 
 #include "na-tray-manager.h"
 
-#if defined (GDK_WINDOWING_X11)
-#include <gdk/gdkx.h>
 #include <X11/Xatom.h>
-#elif defined (GDK_WINDOWING_WIN32)
-#include <gdk/gdkwin32.h>
-#endif
-#include <gtk/gtk.h>
+#include <X11/Xutil.h>
 
 /* Signals */
 enum
@@ -43,36 +38,53 @@ enum
   LAST_SIGNAL
 };
 
-enum {
+static guint manager_signals[LAST_SIGNAL];
+
+enum
+{
   PROP_0,
-  PROP_ORIENTATION
+  PROP_X11_DISPLAY,
+  N_PROPS,
 };
 
+static GParamSpec *props[N_PROPS];
+
 typedef struct
 {
   long id, len;
   long remaining_len;
-  
+
   long timeout;
   char *str;
-#ifdef GDK_WINDOWING_X11
   Window window;
-#endif
 } PendingMessage;
 
-static guint manager_signals[LAST_SIGNAL];
+struct _NaTrayManager
+{
+  GObject parent_instance;
+
+  MetaX11Display *x11_display;
+
+  Atom selection_atom;
+  Atom opcode_atom;
+  Atom message_data_atom;
+
+  Window window;
+  ClutterColor fg;
+  ClutterColor error;
+  ClutterColor warning;
+  ClutterColor success;
+
+  unsigned int event_func_id;
+
+  GList *messages;
+  GHashTable *children;
+};
 
 #define SYSTEM_TRAY_REQUEST_DOCK    0
 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
 
-#define SYSTEM_TRAY_ORIENTATION_HORZ 0
-#define SYSTEM_TRAY_ORIENTATION_VERT 1
-
-#ifdef GDK_WINDOWING_X11
-static gboolean na_tray_manager_check_running_screen_x11 (void);
-#endif
-
 static void na_tray_manager_finalize     (GObject      *object);
 static void na_tray_manager_set_property (GObject      *object,
                                          guint         prop_id,
@@ -90,8 +102,8 @@ G_DEFINE_TYPE (NaTrayManager, na_tray_manager, G_TYPE_OBJECT)
 static void
 na_tray_manager_init (NaTrayManager *manager)
 {
-  manager->invisible = NULL;
-  manager->socket_table = g_hash_table_new (NULL, NULL);
+  manager->window = None;
+  manager->children = g_hash_table_new (NULL, NULL);
 
   manager->fg.red = 0;
   manager->fg.green = 0;
@@ -121,83 +133,69 @@ na_tray_manager_class_init (NaTrayManagerClass *klass)
   gobject_class->set_property = na_tray_manager_set_property;
   gobject_class->get_property = na_tray_manager_get_property;
 
-  g_object_class_install_property (gobject_class,
-                                  PROP_ORIENTATION,
-                                  g_param_spec_enum ("orientation",
-                                                     "orientation",
-                                                     "orientation",
-                                                     GTK_TYPE_ORIENTATION,
-                                                     GTK_ORIENTATION_HORIZONTAL,
-                                                     G_PARAM_READWRITE |
-                                                     G_PARAM_STATIC_STRINGS |
-                                                     G_PARAM_CONSTRUCT));
-  
   manager_signals[TRAY_ICON_ADDED] =
     g_signal_new ("tray_icon_added",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_added),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST, 0,
                   NULL, NULL, NULL,
-                 G_TYPE_NONE, 1,
-                 GTK_TYPE_SOCKET);
+                  G_TYPE_NONE, 1,
+                  NA_TYPE_TRAY_CHILD);
 
   manager_signals[TRAY_ICON_REMOVED] =
     g_signal_new ("tray_icon_removed",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_removed),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST, 0,
                   NULL, NULL, NULL,
-                 G_TYPE_NONE, 1,
-                 GTK_TYPE_SOCKET);
+                  G_TYPE_NONE, 1,
+                  NA_TYPE_TRAY_CHILD);
   manager_signals[MESSAGE_SENT] =
     g_signal_new ("message_sent",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (NaTrayManagerClass, message_sent),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST, 0,
                   NULL, NULL, NULL,
-                 G_TYPE_NONE, 4,
-                 GTK_TYPE_SOCKET,
-                 G_TYPE_STRING,
-                 G_TYPE_LONG,
-                 G_TYPE_LONG);
+                  G_TYPE_NONE, 4,
+                  NA_TYPE_TRAY_CHILD,
+                  G_TYPE_STRING,
+                  G_TYPE_LONG,
+                  G_TYPE_LONG);
   manager_signals[MESSAGE_CANCELLED] =
     g_signal_new ("message_cancelled",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (NaTrayManagerClass, message_cancelled),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST, 0,
                   NULL, NULL, NULL,
-                 G_TYPE_NONE, 2,
-                 GTK_TYPE_SOCKET,
-                 G_TYPE_LONG);
+                  G_TYPE_NONE, 2,
+                  NA_TYPE_TRAY_CHILD,
+                  G_TYPE_LONG);
   manager_signals[LOST_SELECTION] =
     g_signal_new ("lost_selection",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (NaTrayManagerClass, lost_selection),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST, 0,
                   NULL, NULL, NULL,
-                 G_TYPE_NONE, 0);
-
-#if defined (GDK_WINDOWING_X11)
-  /* Nothing */
-#elif defined (GDK_WINDOWING_WIN32)
-  g_warning ("Port NaTrayManager to Win32");
-#else
-  g_warning ("Port NaTrayManager to this GTK+ backend");
-#endif
+                  G_TYPE_NONE, 0);
+
+  props[PROP_X11_DISPLAY] =
+    g_param_spec_object ("x11-display",
+                         "x11-display",
+                         "x11-display",
+                         META_TYPE_X11_DISPLAY,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, props);
 }
 
 static void
 na_tray_manager_finalize (GObject *object)
 {
   NaTrayManager *manager;
-  
+
   manager = NA_TRAY_MANAGER (object);
 
   na_tray_manager_unmanage (manager);
 
   g_list_free (manager->messages);
-  g_hash_table_destroy (manager->socket_table);
-  
+  g_hash_table_destroy (manager->children);
+
   G_OBJECT_CLASS (na_tray_manager_parent_class)->finalize (object);
 }
 
@@ -211,8 +209,8 @@ na_tray_manager_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_ORIENTATION:
-      na_tray_manager_set_orientation (manager, g_value_get_enum (value));
+    case PROP_X11_DISPLAY:
+      manager->x11_display = g_value_get_object (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -230,8 +228,8 @@ na_tray_manager_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_ORIENTATION:
-      g_value_set_enum (value, manager->orientation);
+    case PROP_X11_DISPLAY:
+      g_value_set_object (value, manager->x11_display);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -240,26 +238,24 @@ na_tray_manager_get_property (GObject    *object,
 }
 
 NaTrayManager *
-na_tray_manager_new (void)
+na_tray_manager_new (MetaX11Display *x11_display)
 {
-  NaTrayManager *manager;
-
-  manager = g_object_new (NA_TYPE_TRAY_MANAGER, NULL);
-
-  return manager;
+  return g_object_new (NA_TYPE_TRAY_MANAGER,
+                       "x11-display", x11_display,
+                       NULL);
 }
 
-#ifdef GDK_WINDOWING_X11
-
 static gboolean
-na_tray_manager_plug_removed (GtkSocket       *socket,
-                             NaTrayManager   *manager)
+na_tray_manager_plug_removed (NaTrayChild   *tray_child,
+                              NaTrayManager *manager)
 {
-  NaTrayChild *child = NA_TRAY_CHILD (socket);
+  Window icon_window;
+
+  icon_window = na_xembed_get_plug_window (NA_XEMBED (tray_child));
 
-  g_hash_table_remove (manager->socket_table,
-                       GINT_TO_POINTER (child->icon_window));
-  g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
+  g_hash_table_remove (manager->children,
+                       GINT_TO_POINTER (icon_window));
+  g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, tray_child);
 
   /* This destroys the socket. */
   return FALSE;
@@ -267,49 +263,40 @@ na_tray_manager_plug_removed (GtkSocket       *socket,
 
 static void
 na_tray_manager_handle_dock_request (NaTrayManager       *manager,
-                                    XClientMessageEvent *xevent)
+                                     XClientMessageEvent *xevent)
 {
   Window icon_window = xevent->data.l[2];
-  GtkWidget *child;
+  NaTrayChild *child;
 
-  if (g_hash_table_lookup (manager->socket_table,
+  if (g_hash_table_lookup (manager->children,
                            GINT_TO_POINTER (icon_window)))
     {
       /* We already got this notification earlier, ignore this one */
       return;
     }
 
-  child = na_tray_child_new (manager->screen, icon_window);
+  child = na_tray_child_new (manager->x11_display, icon_window);
   if (child == NULL) /* already gone or other error */
     return;
 
   g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0,
-                child);
-
-  /* If the child wasn't attached, then destroy it */
-
-  if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child))))
-    {
-      gtk_widget_destroy (child);
-      return;
-    }
+                 child);
 
-  g_signal_connect (child, "plug_removed",
-                   G_CALLBACK (na_tray_manager_plug_removed), manager);
+  g_signal_connect (child, "plug-removed",
+                    G_CALLBACK (na_tray_manager_plug_removed), manager);
 
-  gtk_socket_add_id (GTK_SOCKET (child), icon_window);
+  na_xembed_add_id (NA_XEMBED (child), icon_window);
 
-  if (!gtk_socket_get_plug_window (GTK_SOCKET (child)))
+  if (!na_xembed_get_plug_window (NA_XEMBED (child)))
     {
       /* Embedding failed, we won't get a plug-removed signal */
-      /* This signal destroys the socket */
+      /* This signal destroys the tray child */
       g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
       return;
     }
 
-  g_hash_table_insert (manager->socket_table,
+  g_hash_table_insert (manager->children,
                        GINT_TO_POINTER (icon_window), child);
-  gtk_widget_show (child);
 }
 
 static void
@@ -321,11 +308,11 @@ pending_message_free (PendingMessage *message)
 
 static void
 na_tray_manager_handle_message_data (NaTrayManager       *manager,
-                                    XClientMessageEvent *xevent)
+                                     XClientMessageEvent *xevent)
 {
   GList *p;
-  int    len;
-  
+  int len;
+
   /* Try to see if we can find the pending message in the list */
   for (p = manager->messages; p; p = p->next)
     {
@@ -340,21 +327,23 @@ na_tray_manager_handle_message_data (NaTrayManager       *manager,
                  &xevent->data, len);
          msg->remaining_len -= len;
 
-         if (msg->remaining_len == 0)
-           {
-             GtkSocket *socket;
+          if (msg->remaining_len == 0)
+            {
+              NaTrayChild *child;
 
-             socket = g_hash_table_lookup (manager->socket_table,
-                                            GINT_TO_POINTER (msg->window));
+              child = g_hash_table_lookup (manager->children,
+                                           GINT_TO_POINTER (msg->window));
 
-             if (socket)
-                 g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0,
-                                socket, msg->str, msg->id, msg->timeout);
+              if (child)
+                {
+                  g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0,
+                                 child, msg->str, msg->id, msg->timeout);
+                }
 
-             pending_message_free (msg);
-             manager->messages = g_list_remove_link (manager->messages, p);
+              pending_message_free (msg);
+              manager->messages = g_list_remove_link (manager->messages, p);
               g_list_free_1 (p);
-           }
+            }
 
           break;
        }
@@ -363,24 +352,22 @@ na_tray_manager_handle_message_data (NaTrayManager       *manager,
 
 static void
 na_tray_manager_handle_begin_message (NaTrayManager       *manager,
-                                     XClientMessageEvent *xevent)
+                                      XClientMessageEvent *xevent)
 {
-  GtkSocket      *socket;
-  GList          *p;
+  NaTrayChild *child;
+  GList *p;
   PendingMessage *msg;
-  long            timeout;
-  long            len;
-  long            id;
+  long timeout, len, id;
 
-  socket = g_hash_table_lookup (manager->socket_table,
-                                GINT_TO_POINTER (xevent->window));
+  child = g_hash_table_lookup (manager->children,
+                               GINT_TO_POINTER (xevent->window));
   /* we don't know about this tray icon, so ignore the message */
-  if (!socket)
+  if (!child)
     return;
 
   timeout = xevent->data.l[2];
-  len     = xevent->data.l[3];
-  id      = xevent->data.l[4];
+  len = xevent->data.l[3];
+  id = xevent->data.l[4];
 
   /* Check if the same message is already in the queue and remove it if so */
   for (p = manager->messages; p; p = p->next)
@@ -401,7 +388,7 @@ na_tray_manager_handle_begin_message (NaTrayManager       *manager,
   if (len == 0)
     {
       g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0,
-                     socket, "", id, timeout);
+                     child, "", id, timeout);
     }
   else
     {
@@ -420,14 +407,14 @@ na_tray_manager_handle_begin_message (NaTrayManager       *manager,
 
 static void
 na_tray_manager_handle_cancel_message (NaTrayManager       *manager,
-                                      XClientMessageEvent *xevent)
+                                       XClientMessageEvent *xevent)
 {
-  GList     *p;
-  GtkSocket *socket;
-  long       id;
+  NaTrayChild *child;
+  GList *p;
+  long id;
 
   id = xevent->data.l[2];
-  
+
   /* Check if the message is in the queue and remove it if so */
   for (p = manager->messages; p; p = p->next)
     {
@@ -443,166 +430,98 @@ na_tray_manager_handle_cancel_message (NaTrayManager       *manager,
        }
     }
 
-  socket = g_hash_table_lookup (manager->socket_table,
-                                GINT_TO_POINTER (xevent->window));
-  
-  if (socket)
+  child = g_hash_table_lookup (manager->children,
+                               GINT_TO_POINTER (xevent->window));
+
+  if (child)
     {
       g_signal_emit (manager, manager_signals[MESSAGE_CANCELLED], 0,
-                    socket, xevent->data.l[2]);
+                     child, xevent->data.l[2]);
     }
 }
 
-static GdkFilterReturn
-na_tray_manager_window_filter (GdkXEvent *xev,
-                               GdkEvent  *event,
-                               gpointer   data)
+static void
+na_tray_manager_event_func (MetaX11Display *x11_display,
+                            XEvent         *xevent,
+                            gpointer        data)
 {
-  XEvent        *xevent = (GdkXEvent *)xev;
   NaTrayManager *manager = data;
 
-  if (xevent->type == ClientMessage)
+  if (xevent->type == ClientMessage &&
+      xevent->xany.window == manager->window)
     {
       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_REQUEST_DOCK */
       if (xevent->xclient.message_type == manager->opcode_atom &&
-          xevent->xclient.data.l[1]    == SYSTEM_TRAY_REQUEST_DOCK)
-       {
+          xevent->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK)
+        {
           na_tray_manager_handle_dock_request (manager,
                                                (XClientMessageEvent *) xevent);
-          return GDK_FILTER_REMOVE;
-       }
+        }
       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_BEGIN_MESSAGE */
       else if (xevent->xclient.message_type == manager->opcode_atom &&
-               xevent->xclient.data.l[1]    == SYSTEM_TRAY_BEGIN_MESSAGE)
+               xevent->xclient.data.l[1] == SYSTEM_TRAY_BEGIN_MESSAGE)
         {
           na_tray_manager_handle_begin_message (manager,
-                                                (XClientMessageEvent *) event);
-          return GDK_FILTER_REMOVE;
+                                                (XClientMessageEvent *) xevent);
         }
       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_CANCEL_MESSAGE */
       else if (xevent->xclient.message_type == manager->opcode_atom &&
-               xevent->xclient.data.l[1]    == SYSTEM_TRAY_CANCEL_MESSAGE)
+               xevent->xclient.data.l[1] == SYSTEM_TRAY_CANCEL_MESSAGE)
         {
           na_tray_manager_handle_cancel_message (manager,
-                                                 (XClientMessageEvent *) event);
-          return GDK_FILTER_REMOVE;
+                                                 (XClientMessageEvent *) xevent);
         }
       /* _NET_SYSTEM_TRAY_MESSAGE_DATA */
       else if (xevent->xclient.message_type == manager->message_data_atom)
         {
           na_tray_manager_handle_message_data (manager,
-                                               (XClientMessageEvent *) event);
-          return GDK_FILTER_REMOVE;
+                                               (XClientMessageEvent *) xevent);
         }
     }
-  else if (xevent->type == SelectionClear)
+  else if (xevent->type == SelectionClear &&
+           xevent->xany.window == manager->window)
     {
       g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
       na_tray_manager_unmanage (manager);
     }
-
-  return GDK_FILTER_CONTINUE;
-}
-
-#if 0
-//FIXME investigate why this doesn't work
-static gboolean
-na_tray_manager_selection_clear_event (GtkWidget         *widget,
-                                       GdkEventSelection *event,
-                                       NaTrayManager     *manager)
-{
-  g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
-  na_tray_manager_unmanage (manager);
-
-  return FALSE;
 }
-#endif
-#endif  
 
 static void
 na_tray_manager_unmanage (NaTrayManager *manager)
 {
-#ifdef GDK_WINDOWING_X11
-  GdkDisplay *display;
-  guint32     timestamp;
-  GtkWidget  *invisible;
-  GdkWindow  *window;
+  Display *xdisplay;
 
-  if (manager->invisible == NULL)
+  if (manager->window == None)
     return;
 
-  invisible = manager->invisible;
-  window = gtk_widget_get_window (invisible);
+  xdisplay = meta_x11_display_get_xdisplay (manager->x11_display);
 
-  g_assert (GTK_IS_INVISIBLE (invisible));
-  g_assert (gtk_widget_get_realized (invisible));
-  g_assert (GDK_IS_WINDOW (window));
-  
-  display = gtk_widget_get_display (invisible);
-  
-  if (gdk_selection_owner_get_for_display (display, manager->selection_atom) ==
-      window)
+  if (XGetSelectionOwner (xdisplay, manager->selection_atom) == manager->window)
     {
-      timestamp = gdk_x11_get_server_time (window);
-      gdk_selection_owner_set_for_display (display,
-                                           NULL,
-                                           manager->selection_atom,
-                                           timestamp,
-                                           TRUE);
+      XSetSelectionOwner (xdisplay,
+                          manager->selection_atom,
+                          None,
+                          CurrentTime);
     }
 
-  gdk_window_remove_filter (window,
-                            na_tray_manager_window_filter, manager);  
-
-  manager->invisible = NULL; /* prior to destroy for reentrancy paranoia */
-  gtk_widget_destroy (invisible);
-  g_object_unref (G_OBJECT (invisible));
-#endif
-}
+  meta_x11_display_remove_event_func (manager->x11_display,
+                                      manager->event_func_id);
+  manager->event_func_id = 0;
 
-static void
-na_tray_manager_set_orientation_property (NaTrayManager *manager)
-{
-#ifdef GDK_WINDOWING_X11
-  GdkWindow  *window;
-  GdkDisplay *display;
-  Atom        orientation_atom;
-  gulong      data[1];
-
-  g_return_if_fail (manager->invisible != NULL);
-  window = gtk_widget_get_window (manager->invisible);
-  g_return_if_fail (window != NULL);
-
-  display = gtk_widget_get_display (manager->invisible);
-  orientation_atom = gdk_x11_get_xatom_by_name_for_display (display,
-                                                            "_NET_SYSTEM_TRAY_ORIENTATION");
-
-  data[0] = manager->orientation == GTK_ORIENTATION_HORIZONTAL ?
-               SYSTEM_TRAY_ORIENTATION_HORZ :
-               SYSTEM_TRAY_ORIENTATION_VERT;
-
-  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
-                  GDK_WINDOW_XID (window),
-                   orientation_atom,
-                  XA_CARDINAL, 32,
-                  PropModeReplace,
-                  (guchar *) &data, 1);
-#endif
+  XDestroyWindow (xdisplay, manager->window);
+  manager->window = None;
 }
 
 static void
 na_tray_manager_set_visual_property (NaTrayManager *manager)
 {
-#ifdef GDK_WINDOWING_X11
-  GdkWindow  *window;
-  GdkDisplay *display;
-  Visual     *xvisual;
-  Atom        visual_atom;
-  gulong      data[1];
+  Display *xdisplay;
+  Atom visual_atom;
+  XVisualInfo xvisual_info;
+  gulong data[1];
+  int result;
 
-  g_return_if_fail (manager->invisible != NULL);
-  window = gtk_widget_get_window (manager->invisible);
-  g_return_if_fail (window != NULL);
+  g_return_if_fail (manager->window != None);
 
   /* The visual property is a hint to the tray icons as to what visual they
    * should use for their windows. If the X server has RGBA colormaps, then
@@ -611,49 +530,35 @@ na_tray_manager_set_visual_property (NaTrayManager *manager)
    * the icon to use our colormap, and we'll do some hacks with parent
    * relative backgrounds to simulate transparency.
    */
+  xdisplay = meta_x11_display_get_xdisplay (manager->x11_display);
+  visual_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_VISUAL", False);
 
-  display = gtk_widget_get_display (manager->invisible);
-  visual_atom = gdk_x11_get_xatom_by_name_for_display (display,
-                                                      "_NET_SYSTEM_TRAY_VISUAL");
+  result = XMatchVisualInfo (xdisplay, DefaultScreen (xdisplay), 32, TrueColor, &xvisual_info);
 
-  if (gdk_screen_get_rgba_visual (manager->screen) != NULL)
-    xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen));
+  if (result == Success)
+    data[0] = xvisual_info.visualid;
   else
-    {
-      /* We actually want the visual of the tray where the icons will
-       * be embedded. In almost all cases, this will be the same as the visual
-       * of the screen.
-       */
-      xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (manager->screen));
-    }
+    data[0] = XVisualIDFromVisual (DefaultVisual (xdisplay, DefaultScreen (xdisplay)));
 
-  data[0] = XVisualIDFromVisual (xvisual);
-
-  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
-                   GDK_WINDOW_XID (window),
+  XChangeProperty (xdisplay,
+                   manager->window,
                    visual_atom,
                    XA_VISUALID, 32,
                    PropModeReplace,
                    (guchar *) &data, 1);
-#endif
 }
 
 static void
 na_tray_manager_set_colors_property (NaTrayManager *manager)
 {
-#ifdef GDK_WINDOWING_X11
-  GdkWindow  *window;
-  GdkDisplay *display;
-  Atom        atom;
-  gulong      data[12];
+  Display *xdisplay;
+  Atom atom;
+  gulong data[12];
 
-  g_return_if_fail (manager->invisible != NULL);
-  window = gtk_widget_get_window (manager->invisible);
-  g_return_if_fail (window != NULL);
+  g_return_if_fail (manager->window != None);
 
-  display = gtk_widget_get_display (manager->invisible);
-  atom = gdk_x11_get_xatom_by_name_for_display (display,
-                                                "_NET_SYSTEM_TRAY_COLORS");
+  xdisplay = meta_x11_display_get_xdisplay (manager->x11_display);
+  atom = XInternAtom (xdisplay,  "_NET_SYSTEM_TRAY_COLORS", False);
 
   data[0] = manager->fg.red * 0x101;
   data[1] = manager->fg.green * 0x101;
@@ -668,194 +573,87 @@ na_tray_manager_set_colors_property (NaTrayManager *manager)
   data[10] = manager->success.green * 0x101;
   data[11] = manager->success.blue * 0x101;
 
-  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
-                   GDK_WINDOW_XID (window),
+  XChangeProperty (xdisplay,
+                   manager->window,
                    atom,
                    XA_CARDINAL, 32,
                    PropModeReplace,
                    (guchar *) &data, 12);
-#endif
 }
 
-#ifdef GDK_WINDOWING_X11
-
-static gboolean
-na_tray_manager_manage_screen_x11 (NaTrayManager *manager)
+gboolean
+na_tray_manager_manage (NaTrayManager *manager)
 {
-  GdkDisplay *display;
-  GdkScreen *screen;
-  Screen *xscreen;
-  GtkWidget *invisible;
-  GdkWindow *window;
-  char *selection_atom_name;
-  guint32 timestamp;
-  
+  Display *xdisplay;
+
   g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), FALSE);
-  g_return_val_if_fail (manager->screen == NULL, FALSE);
 
-  /* If there's already a manager running on the screen
-   * we can't create another one.
-   */
-#if 0
-  if (na_tray_manager_check_running_screen_x11 ())
-    return FALSE;
-#endif
-  
-  screen = gdk_screen_get_default ();
-  manager->screen = screen;
+  xdisplay = meta_x11_display_get_xdisplay (manager->x11_display);
 
-  display = gdk_screen_get_display (screen);
-  xscreen = GDK_SCREEN_XSCREEN (screen);
-  
-  invisible = gtk_invisible_new_for_screen (screen);
-  gtk_widget_realize (invisible);
-  
-  gtk_widget_add_events (invisible,
-                         GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
+  meta_x11_error_trap_push (manager->x11_display);
+  manager->window = XCreateSimpleWindow (xdisplay,
+                                         XDefaultRootWindow (xdisplay),
+                                         0, 0, 1, 1,
+                                         0, 0, 0);
+  XSelectInput (xdisplay, manager->window,
+                StructureNotifyMask | PropertyChangeMask);
 
-  selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
-                                         gdk_x11_get_default_screen ());
-  manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
-  g_free (selection_atom_name);
+  if (meta_x11_error_trap_pop_with_return (manager->x11_display) ||
+      !manager->window)
+    return FALSE;
 
-  manager->invisible = invisible;
-  g_object_ref (G_OBJECT (manager->invisible));
+  manager->selection_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_S0", False);
 
-  na_tray_manager_set_orientation_property (manager);
   na_tray_manager_set_visual_property (manager);
   na_tray_manager_set_colors_property (manager);
-  
-  window = gtk_widget_get_window (invisible);
 
-  timestamp = gdk_x11_get_server_time (window);
+  meta_x11_error_trap_push (manager->x11_display);
+
+  XSetSelectionOwner (xdisplay, manager->selection_atom,
+                     manager->window, CurrentTime);
 
   /* Check if we could set the selection owner successfully */
-  if (gdk_selection_owner_set_for_display (display,
-                                           window,
-                                           manager->selection_atom,
-                                           timestamp,
-                                           TRUE))
+  if (!meta_x11_error_trap_pop_with_return (manager->x11_display))
     {
       XClientMessageEvent xev;
-      GdkAtom             opcode_atom;
-      GdkAtom             message_data_atom;
 
       xev.type = ClientMessage;
-      xev.window = RootWindowOfScreen (xscreen);
-      xev.message_type = gdk_x11_get_xatom_by_name_for_display (display,
-                                                                "MANAGER");
+      xev.window = XDefaultRootWindow (xdisplay);
+      xev.message_type = XInternAtom (xdisplay, "MANAGER", False);
 
       xev.format = 32;
-      xev.data.l[0] = timestamp;
-      xev.data.l[1] = gdk_x11_atom_to_xatom_for_display (display,
-                                                         manager->selection_atom);
-      xev.data.l[2] = GDK_WINDOW_XID (window);
-      xev.data.l[3] = 0;       /* manager specific data */
-      xev.data.l[4] = 0;       /* manager specific data */
-
-      XSendEvent (GDK_DISPLAY_XDISPLAY (display),
-                 RootWindowOfScreen (xscreen),
-                 False, StructureNotifyMask, (XEvent *)&xev);
-
-      opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE);
-      manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display,
-                                                                opcode_atom);
-
-      message_data_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_MESSAGE_DATA",
-                                           FALSE);
-      manager->message_data_atom = gdk_x11_atom_to_xatom_for_display (display,
-                                                                      message_data_atom);
-
-      /* Add a window filter */
-#if 0
-      /* This is for when we lose the selection of _NET_SYSTEM_TRAY_Sx */
-      g_signal_connect (invisible, "selection-clear-event",
-                        G_CALLBACK (na_tray_manager_selection_clear_event),
-                        manager);
-#endif
-      gdk_window_add_filter (window,
-                             na_tray_manager_window_filter, manager);
+      xev.data.l[0] = CurrentTime;
+      xev.data.l[1] = manager->selection_atom;
+      xev.data.l[2] = manager->window;
+      xev.data.l[3] = 0; /* manager specific data */
+      xev.data.l[4] = 0; /* manager specific data */
+
+      XSendEvent (xdisplay,
+                  XDefaultRootWindow (xdisplay),
+                  False, StructureNotifyMask, (XEvent *)&xev);
+
+      manager->opcode_atom =
+        XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_OPCODE", False);
+      manager->message_data_atom =
+        XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
+
+      /* Add an event filter */
+      manager->event_func_id =
+        meta_x11_display_add_event_func (manager->x11_display,
+                                         na_tray_manager_event_func,
+                                         manager,
+                                         NULL);
       return TRUE;
     }
   else
     {
-      gtk_widget_destroy (invisible);
-      g_object_unref (invisible);
-      manager->invisible = NULL;
+      XDestroyWindow (xdisplay, manager->window);
+      manager->window = None;
 
-      manager->screen = NULL;
- 
       return FALSE;
     }
 }
 
-#endif
-
-gboolean
-na_tray_manager_manage_screen (NaTrayManager *manager)
-{
-  g_return_val_if_fail (manager->screen == NULL, FALSE);
-
-#ifdef GDK_WINDOWING_X11
-  return na_tray_manager_manage_screen_x11 (manager);
-#else
-  return FALSE;
-#endif
-}
-
-#ifdef GDK_WINDOWING_X11
-
-static gboolean
-na_tray_manager_check_running_screen_x11 (void)
-{
-  GdkDisplay *display;
-  GdkScreen *screen;
-  Atom selection_atom;
-  char *selection_atom_name;
-
-  screen = gdk_screen_get_default ();
-  display = gdk_screen_get_display (screen);
-  selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
-                                         gdk_x11_get_default_screen ());
-  selection_atom = gdk_x11_get_xatom_by_name_for_display (display,
-                                                          selection_atom_name);
-  g_free (selection_atom_name);
-
-  if (XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
-                          selection_atom) != None)
-    return TRUE;
-  else
-    return FALSE;
-}
-
-#endif
-
-gboolean
-na_tray_manager_check_running (void)
-{
-#ifdef GDK_WINDOWING_X11
-  return na_tray_manager_check_running_screen_x11 ();
-#else
-  return FALSE;
-#endif
-}
-
-void
-na_tray_manager_set_orientation (NaTrayManager  *manager,
-                                GtkOrientation  orientation)
-{
-  g_return_if_fail (NA_IS_TRAY_MANAGER (manager));
-
-  if (manager->orientation != orientation)
-    {
-      manager->orientation = orientation;
-
-      na_tray_manager_set_orientation_property (manager);
-
-      g_object_notify (G_OBJECT (manager), "orientation");
-    }
-}
-
 void
 na_tray_manager_set_colors (NaTrayManager *manager,
                             ClutterColor  *fg,
@@ -878,11 +676,3 @@ na_tray_manager_set_colors (NaTrayManager *manager,
       na_tray_manager_set_colors_property (manager);
     }
 }
-
-GtkOrientation
-na_tray_manager_get_orientation (NaTrayManager *manager)
-{
-  g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), GTK_ORIENTATION_HORIZONTAL);
-
-  return manager->orientation;
-}
index 727b02d40d83e04ebbb5ba7d6f64c56117973408..a417ce72672c406cc3945191eeb90d1a853a981d 100644 (file)
 #ifndef __NA_TRAY_MANAGER_H__
 #define __NA_TRAY_MANAGER_H__
 
-#ifdef GDK_WINDOWING_X11
-#include <gdk/gdkx.h>
-#endif
-#include <gtk/gtk.h>
 #include <clutter/clutter.h>
 
 #include "na-tray-child.h"
 
 G_BEGIN_DECLS
 
-#define NA_TYPE_TRAY_MANAGER                   (na_tray_manager_get_type ())
-#define NA_TRAY_MANAGER(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManager))
-#define NA_TRAY_MANAGER_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass))
-#define NA_IS_TRAY_MANAGER(obj)                        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_MANAGER))
-#define NA_IS_TRAY_MANAGER_CLASS(klass)                (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_MANAGER))
-#define NA_TRAY_MANAGER_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass))
-       
-typedef struct _NaTrayManager      NaTrayManager;
-typedef struct _NaTrayManagerClass  NaTrayManagerClass;
+#define NA_TYPE_TRAY_MANAGER (na_tray_manager_get_type ())
+G_DECLARE_FINAL_TYPE (NaTrayManager, na_tray_manager, NA, TRAY_MANAGER, GObject)
 
-struct _NaTrayManager
-{
-  GObject parent_instance;
+NaTrayManager *na_tray_manager_new (MetaX11Display *x11_display);
 
-#ifdef GDK_WINDOWING_X11
-  GdkAtom selection_atom;
-  Atom    opcode_atom;
-  Atom    message_data_atom;
-#endif
-  
-  GtkWidget *invisible;
-  GdkScreen *screen;
-  GtkOrientation orientation;
-  ClutterColor fg;
-  ClutterColor error;
-  ClutterColor warning;
-  ClutterColor success;
-
-  GList *messages;
-  GHashTable *socket_table;
-};
-
-struct _NaTrayManagerClass
-{
-  GObjectClass parent_class;
-
-  void (* tray_icon_added)   (NaTrayManager      *manager,
-                             NaTrayChild        *child);
-  void (* tray_icon_removed) (NaTrayManager      *manager,
-                             NaTrayChild        *child);
-
-  void (* message_sent)      (NaTrayManager      *manager,
-                             NaTrayChild        *child,
-                             const gchar        *message,
-                             glong               id,
-                             glong               timeout);
-  
-  void (* message_cancelled) (NaTrayManager      *manager,
-                             NaTrayChild        *child,
-                             glong               id);
-
-  void (* lost_selection)    (NaTrayManager      *manager);
-};
-
-GType           na_tray_manager_get_type        (void);
-
-gboolean        na_tray_manager_check_running   (void);
-NaTrayManager  *na_tray_manager_new             (void);
-gboolean        na_tray_manager_manage_screen   (NaTrayManager      *manager);
-void            na_tray_manager_set_orientation (NaTrayManager      *manager,
-                                                GtkOrientation      orientation);
-GtkOrientation  na_tray_manager_get_orientation (NaTrayManager      *manager);
-void            na_tray_manager_set_colors      (NaTrayManager      *manager,
-                                                ClutterColor       *fg,
-                                                ClutterColor       *error,
-                                                ClutterColor       *warning,
-                                                ClutterColor       *success);
+gboolean na_tray_manager_manage (NaTrayManager *manager);
 
+void na_tray_manager_set_colors (NaTrayManager *manager,
+                                 ClutterColor  *fg,
+                                 ClutterColor  *error,
+                                 ClutterColor  *warning,
+                                 ClutterColor  *success);
 
 G_END_DECLS